package com.mobeedom.android.justinstalled;

import static com.mobeedom.android.justinstalled.AppSingleton.LOG_TAG;
import static com.mobeedom.android.justinstalled.AppSingleton.NUM_APPS;

import java.io.File;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;

import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.text.Html;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;

import com.j256.ormlite.dao.RuntimeExceptionDao;
import com.j256.ormlite.stmt.QueryBuilder;
import com.j256.ormlite.table.TableUtils;
import com.mobeedom.android.justinstalled.db.DatabaseHelper;
import com.mobeedom.android.justinstalled.db.InstalledAppInfo;

public class MainActivity extends Activity implements OnSharedPreferenceChangeListener {
	private static final String IS_FIRST_RUN = "isFirstRun";
	private static final int ABOUT_DIALOG = 1;

	public static SimpleDateFormat dateFormatter = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");

	protected RuntimeExceptionDao<InstalledAppInfo, Integer> daoInstalledAppInfo;

	protected ListView listView;
	protected TextView txtTitle;
	protected ImageView imgAbout;
	protected ImageView imgSettings;
	protected ProgressBar progressBar;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		listView = (ListView) findViewById(R.id.ListViewId);
		listView.setOnItemClickListener(new OnItemClickListener() {
			@Override
			public void onItemClick(AdapterView<?> list, View view, int position, long id) {
				Log.i(LOG_TAG, "onListItemClick: " + position);
				launchApp((InstalledAppInfo) list.getItemAtPosition(position));
			}
		});

		listView.setOnItemLongClickListener(new OnItemLongClickListener() {
			@Override
			public boolean onItemLongClick(AdapterView<?> list, View view, int position, long id) {
				Log.i(LOG_TAG, "onListItemLongClick: " + position);
				uninstallApp((InstalledAppInfo) list.getItemAtPosition(position));
				return true;
			}
		});
		imgAbout = (ImageView) findViewById(R.id.imgAbout);
		imgAbout.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				AboutDialog about = new AboutDialog(MainActivity.this);
				about.setTitle("About");
				about.show();
				// showDialog(ABOUT_DIALOG);
			}
		});
		imgSettings = (ImageView) findViewById(R.id.imgOptions);
		imgSettings.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				showPreferences();
			}
		});

		progressBar = (ProgressBar) findViewById(R.id.progressBar);

		txtTitle = (TextView) findViewById(R.id.txtTitle);
		daoInstalledAppInfo = DatabaseHelper.getHelper(getApplicationContext()).getDaoInstalledAppInfoRuntime();
		PreferenceManager.getDefaultSharedPreferences(this).registerOnSharedPreferenceChangeListener(this);
		AppRater.app_launched(this);		

	}

	@Override
	@SuppressLint("NewApi")
	protected void onResume() {
		super.onResume();
		progressBar.setVisibility(View.VISIBLE);
		ArrayList<InstalledAppInfo> dummyToShow = new ArrayList<InstalledAppInfo>();

		for (int i = 0; i < NUM_APPS; i++) {
			dummyToShow.add(new InstalledAppInfo());
		}

		listView.setAdapter(new InstalledAppAdapter(MainActivity.this, android.R.layout.simple_list_item_1, dummyToShow));

		boolean isFirstRun = readPreferences();
		txtTitle.setText(getString(R.string.list_title, NUM_APPS));
		new AsyncTask<Boolean, Void, Boolean>() {
			ArrayList<InstalledAppInfo> appsToShow = null;

			@Override
			protected Boolean doInBackground(Boolean... params) {
				try {
					if (!params[0]) {
						appsToShow = loadCachedAppsList();
					} else {
						appsToShow = initAppsList();
					}
				} catch (SQLException e) {
					Log.e(LOG_TAG, e.getMessage());
					return false;
				}
				return true;
			}

			@SuppressLint("NewApi")
			@Override
			protected void onPostExecute(Boolean result) {
				listView.setAdapter(new InstalledAppAdapter(MainActivity.this, android.R.layout.simple_list_item_1,
						appsToShow));

				updateIsFirstRun(false);
				progressBar.setVisibility(View.INVISIBLE);
			}
		}.execute(isFirstRun);
	}

	protected void showPreferences() {
		Intent prefs = new Intent(this, Preferences.class);
		startActivity(prefs);
	}

	protected boolean readPreferences() {
		SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);

		boolean isFirstRun = prefs.getBoolean(IS_FIRST_RUN, true);
		NUM_APPS = Integer.parseInt(prefs.getString("num_apps", "" + NUM_APPS));
		return isFirstRun;
	}

	public ArrayList<InstalledAppInfo> loadCachedAppsList() throws SQLException {
		Log.d(LOG_TAG, "loadCachedAppsList");

		ArrayList<InstalledAppInfo> appsToShow = new ArrayList<InstalledAppInfo>();
		QueryBuilder<InstalledAppInfo, Integer> qb = daoInstalledAppInfo.queryBuilder();
		qb.orderBy("installDate", false);
		qb.limit(NUM_APPS);
		appsToShow.addAll(qb.query());
		return appsToShow;
	}

	public ArrayList<InstalledAppInfo> initAppsList() throws SQLException {
		Log.d(LOG_TAG, "initappsList");

		ArrayList<PInfo> apps = new ArrayList<PInfo>();
		apps = getInstalledApps(false);
		Collections.sort(apps);

		TableUtils.clearTable(DatabaseHelper.getHelper(getApplicationContext()).getConnectionSource(),
				InstalledAppInfo.class);
		ArrayList<InstalledAppInfo> appsToShow = new ArrayList<InstalledAppInfo>();
		for (int i = 0; i < apps.size() && i < NUM_APPS; i++) {
			PInfo p = apps.get(i);
			InstalledAppInfo ai = new InstalledAppInfo(p.appname, p.pname, p.installDate.getTime());
			daoInstalledAppInfo.create(ai);
			appsToShow.add(ai);
		}

		return appsToShow;
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		getMenuInflater().inflate(R.menu.activity_main, menu);
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
		case R.id.menu_settings:
			showPreferences();
			break;

		default:
			break;
		}
		return super.onOptionsItemSelected(item);
	}

	@SuppressLint("NewApi")
	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		if (requestCode == 101 && requestCode == Activity.RESULT_OK) {
			progressBar.setVisibility(View.VISIBLE);
			try {
				listView.setAdapter(new InstalledAppAdapter(this, android.R.layout.simple_list_item_1,
						loadCachedAppsList()));
			} catch (SQLException e) {
				e.printStackTrace();
			}
			progressBar.setVisibility(View.INVISIBLE);
		}
	}

	protected Dialog onCreateDialog(int id) {
		switch (id) {
		case ABOUT_DIALOG:
			return createAboutDialog();
		}
		return null;
	}

	protected AlertDialog createAboutDialog() {
		String message = "Sito web: <a href='http://www.mobeedom.com'>www.mobeedom.com</a><br>"
				+ "Twitter: <a href='https://twitter.com/MobeedoM'>@MobeedoM</a>";
		return new AlertDialog.Builder(this).setTitle("MobeedoM").setMessage(Html.fromHtml(message)).create();
	}

	public class InstalledAppAdapter extends ArrayAdapter<InstalledAppInfo> {
		private ArrayList<InstalledAppInfo> apps;

		public InstalledAppAdapter(Context context, int textViewResourceId, ArrayList<InstalledAppInfo> apps) {
			super(context, textViewResourceId, apps);
			this.apps = apps;
		}

		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			View v = convertView;
			// NB: always recycle view
			if (v == null) {
				LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
				v = vi.inflate(R.layout.listitem, null);
			}

			InstalledAppInfo app = apps.get(position);
			if (app != null) {
				TextView appName = (TextView) v.findViewById(R.id.appName);
				TextView installDate = (TextView) v.findViewById(R.id.installDate);
				ImageView appIcon = (ImageView) v.findViewById(R.id.imgLogo);

				if (appName != null) {
					appName.setText((app.getAppName() == null ? "loading..." : app.getAppName()));
				}

				if (installDate != null && app.getAppName() != null) {
					installDate.setText(dateFormatter.format(new Date(app.getInstallDate())));
				}

				if (appIcon != null) {
					try {
						if (app.getAppName() != null)
							appIcon.setImageDrawable(getPackageManager().getApplicationIcon(app.getPackageName()));
						else
							appIcon.setImageResource(R.drawable.ic_question);
					} catch (NameNotFoundException e) {
						Log.e(LOG_TAG, e.getMessage());
					}
				}
			}
			return v;
		}
	}

	public class PInfo implements Comparable<PInfo> {
		private String appname = "";
		private String pname = "";
		private String versionName = "";
		private int versionCode = 0;
		private Date installDate = new Date(0);

		private void prettyPrint() {
			Log.d("MALOTUR", appname + "\t" + pname + "\t" + versionName + "\t" + versionCode + "\t" + installDate);
		}

		@Override
		public int compareTo(PInfo another) {
			return another.installDate.compareTo(installDate);
		}

	}

	@SuppressWarnings("unused")
	private ArrayList<PInfo> getPackages() {
		ArrayList<PInfo> apps = getInstalledApps(false); /* false = no system packages */
		final int max = apps.size();
		for (int i = 0; i < max; i++) {
			apps.get(i).prettyPrint();
		}
		return apps;
	}

	private ArrayList<PInfo> getInstalledApps(boolean getSysPackages) {
		ArrayList<PInfo> res = new ArrayList<PInfo>();
		List<PackageInfo> packs = getPackageManager().getInstalledPackages(0);
		for (int i = 0; i < packs.size(); i++) {
			PackageInfo p = packs.get(i);
			if ((!getSysPackages) && (isSystemPackage(p))) {
				continue;
			}
			PInfo newInfo = new PInfo();
			newInfo.appname = p.applicationInfo.loadLabel(getPackageManager()).toString();
			newInfo.pname = p.packageName;
			newInfo.versionName = p.versionName;
			newInfo.versionCode = p.versionCode;
			p.applicationInfo.loadIcon(getPackageManager());

			if (Build.VERSION.SDK_INT > 8)
				setInstallDate(p, newInfo);
			else
				setUpdateDate(p, newInfo);
			res.add(newInfo);
		}
		return res;
	}

	@TargetApi(9)
	public void setInstallDate(PackageInfo p, PInfo newInfo) {
		newInfo.installDate = new Date(p.firstInstallTime);
	}

	public void setUpdateDate(PackageInfo p, PInfo newInfo) {
		String appFile = p.applicationInfo.sourceDir;
		long installed = new File(appFile).lastModified();
		newInfo.installDate = new Date(installed);
	}

	public void launchApp(InstalledAppInfo i) {
		Intent launchApp = getPackageManager().getLaunchIntentForPackage(i.getPackageName());
		if (launchApp == null) {
			updateIsFirstRun(true);
			onResume();
		} else {
			startActivity(launchApp);
		}
	}

	public void uninstallApp(InstalledAppInfo i) {
		if (i == null) {
			updateIsFirstRun(true);
			onResume();
		} else {
			Intent intent = new Intent(Intent.ACTION_DELETE);
			intent.setData(Uri.parse("package:" + i.getPackageName()));
			startActivity(intent);
			updateIsFirstRun(true);
		}
	}

	private boolean isSystemPackage(PackageInfo pkgInfo) {
		return ((pkgInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) ? true : false;
	}

	@Override
	public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
		if ("num_apps".compareTo(key) == 0) {
			Log.d(LOG_TAG, "onSharedPreferencesChanged - force reload");
			updateIsFirstRun(true);
		}
	}

	public void updateIsFirstRun(boolean mode) {
		SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(MainActivity.this).edit();
		editor.putBoolean(IS_FIRST_RUN, mode);
		editor.commit();
	}
}
